using System;
using UnityEngine;

namespace Gj
{
    public class GridPathPart : BasePart
    {
        private const float hexGridDis = 0.86f;
        private const float defaultGridDis = 1f;
        private MoveStatus _lastMoveStatus = MoveStatus.None;
        private Vector3 _lookPosition = Vector3.zero;
        private LookStatus _lookStatus = LookStatus.None;
        private UnityObject _lookTarget;
        private MoveStatus _moveStatus = MoveStatus.None;

        private Notice _notice;
        private PathNotice _pathNotice;

        private Move _self;
        private bool autoLook;
        private float changeDistance;
        private float process;
        private int cIndex;
        private Vector2Int currentPosition;
        private Vector2Int[] currentPositions;
        private Action endCb;
        private Vector3 endPosition;
        private Vector2Int lastPosition;
        private Vector2Int nextPosition;
        private PathMode mode = PathMode.Default;
        [SerializeField]
        private int index;
        [SerializeField]
        private int pIndex;
        [SerializeField]
        private Vector2Int[] planPositions;
        [SerializeField]
        private Vector2Int position;
        [SerializeField]
        private Vector2Int[] positions;

        private Vector2Int prePosition;

        private Vector3 startPosition;

        [SerializeField]
        private float lastMoveTime;
        private PathStatus status = PathStatus.Stay;
        private PathMoveStep step = PathMoveStep.Start;
        private PathMoveType type = PathMoveType.Start;
        private float stopTime;

        public void SetNotice(Notice notice)
        {
            _notice = notice;
        }

        public void SetPathNotice(PathNotice notice)
        {
            _pathNotice = notice;
        }

        public void WaitStopDoing(Action cb)
        {
            if (IsMoving())
                endCb = cb;
            else
                cb();
        }

        public void Init(Move target)
        {
            _self = target;

            var entity = _self.GetEntity();
            ObjectService.EntityManager.AddComponentData(entity, new MoveStatusData { status = MoveStatus.None });
            ObjectService.EntityManager.AddComponentData(entity, new LookStatusData { status = LookStatus.None });
        }

        public void LookPosition(Vector3 position)
        {
            // if (_lookStatus == LookStatus.Position && _lookPosition == position) return;
            _lookPosition = position;
            _lookStatus = LookStatus.Position;
            var entity = _self.GetEntity();
            ObjectService.EntityManager.AddComponentData(entity, new LookStatusData { status = LookStatus.Position });
            ObjectService.EntityManager.AddComponentData(entity,
                new LookData { position = position, speed = _self.GetRotateSpeed() });
            autoLook = true;
        }

        public void LookDirection(Vector3 direction)
        {
            _lookStatus = LookStatus.Direction;
            var entity = _self.GetEntity();
            ObjectService.EntityManager.AddComponentData(entity, new LookStatusData { status = LookStatus.Direction });
            ObjectService.EntityManager.AddComponentData(entity,
                new LookData { direction = direction, speed = _self.GetRotateSpeed() });
        }

        public void LookTarget(UnityObject target)
        {
            if (target == null) return;
            // if (_lookStatus == LookStatus.Target && _lookTarget == target) return;
            _lookTarget = target;
            _lookStatus = LookStatus.Target;

            var entity = _self.GetEntity();
            ObjectService.EntityManager.AddComponentData(entity, new LookStatusData { status = LookStatus.Target });
            ObjectService.EntityManager.AddComponentData(entity,
                new LookData { target = target.GetEntity(), speed = _self.GetRotateSpeed() });
            autoLook = true;
        }

        public void LookForWard()
        {
            _lookStatus = LookStatus.Direction;
            var entity = _self.GetEntity();
            ObjectService.EntityManager.AddComponentData(entity, new LookStatusData { status = LookStatus.ForWard });
            ObjectService.EntityManager.AddComponentData(entity,
                new LookData { current = _self.GetPosition(), speed = _self.GetRotateSpeed() });
        }


        private void SetPosition(Vector3 position)
        {
            // Debug.LogErrorFormat("SetPosition: {0}", position);
            _moveStatus = MoveStatus.Position;
            var entity = _self.GetEntity();
            // Debug.LogErrorFormat("setPosition: {0}, {1}",position, GetSpeed());
            ObjectService.EntityManager.AddComponentData(entity, new MoveStatusData { status = MoveStatus.Position });
            ObjectService.EntityManager.AddComponentData(entity,
                new MoveData { position = position, speed = GetSpeed()});
        }


        private void SetLine(Vector3 start, Vector3 end, float time = 0)
        {
            // Debug.LogErrorFormat("SetLine: {0} {1}", start, end);
            _moveStatus = MoveStatus.Line;
            var entity = _self.GetEntity();
            // Debug.LogErrorFormat("setPosition: {0}, {1}",position, GetSpeed());
            var distance = Vector3.Distance(start, end);
            ObjectService.EntityManager.AddComponentData(entity, new MoveStatusData { status = MoveStatus.Line });
            if (time > 0)
            {
                // Debug.LogErrorFormat("UnitElement Join: id->{0} gameTime->{1} Time->{2} startTime->{3} endTime->{4} start->{5} end->{6}", _self.GetId(), Global.gameTime, Time.time, lastMoveTime, lastMoveTime + time, start, end);
                ObjectService.EntityManager.AddComponentData(entity,
                    new MoveData { start = start, end = end, progress = 0, waitTime = 0, startTime = lastMoveTime, endTime = lastMoveTime + time });
            }
            else
            {
                ObjectService.EntityManager.AddComponentData(entity,
                    new MoveData { start = start, end = end, speed = GetSpeed(), progress = 0, distance = distance, });
            }
        }

        private void SetTurn(Vector3 start, Vector3 middle, Vector3 end, float time = 0)
        {
            // Debug.LogErrorFormat("SetTurn: {0} {1} {2}", start, middle, end);
            _moveStatus = MoveStatus.Turn;
            var entity = _self.GetEntity();
            // Debug.LogErrorFormat("SetTurn:{0}, {1}, {2}", start, end, GetSpeed());
            var distance = Vector3.Distance(start, middle) + Vector3.Distance(middle, end);
            ObjectService.EntityManager.AddComponentData(entity, new MoveStatusData { status = MoveStatus.Turn });
            if (time > 0)
            {
                // Debug.LogErrorFormat("UnitElement Join: id->{0} gameTime->{1} Time->{2} start->{3} end->{4}", _self.GetId(), Global.gameTime, Time.time, lastMoveTime, lastMoveTime + time);
                ObjectService.EntityManager.AddComponentData(entity,
                    new MoveData { start = start, middle = middle, end = end, progress = 0, waitTime = 0, startTime = lastMoveTime, endTime = lastMoveTime + time });
            }
            else
            {
                ObjectService.EntityManager.AddComponentData(entity,
                    new MoveData { start = start, middle = middle, end = end, speed = GetSpeed(), progress = 0, distance = distance, });
            }
        }

        public void UpdateSpeed(float speed)
        {
            // Debug.LogErrorFormat("updateSpeed {0} {1}", speed, GetSpeed());
            if (speed == GetSpeed()) return;
            var entity = _self.GetEntity();
            var moveData = ObjectService.EntityManager.GetComponentData<MoveData>(entity);
            moveData.speed = speed;
            ObjectService.EntityManager.SetComponentData(entity, moveData);
            // ObjectService.EntityManager.AddComponentData(entity,
            //     new MoveSpeedControlData { _time = 0, time = 0.5f, origin = GetSpeed(), target = speed });
        }

        public void SetSpeed(float speed)
        {
        }

        private float GetSpeed()
        {
            var entity = _self.GetEntity();
            if (ObjectService.EntityManager.HasComponent<MoveData>(entity))
                return ObjectService.EntityManager.GetComponentData<MoveData>(entity).speed;

            return _self.GetMoveSpeed();
        }

        public bool IsMoving()
        {
            // Debug.LogErrorFormat("IsMoving {0}", _moveStatus);
            return _moveStatus != MoveStatus.Stop && _moveStatus != MoveStatus.None;
            var entity = _self.GetEntity();
            if (ObjectService.EntityManager.GetComponentData<MoveStatusData>(entity).status != MoveStatus.None)
                return true;
            return false;
        }

        public bool IsTurn()
        {
            var entity = _self.GetEntity();
            if (ObjectService.EntityManager.GetComponentData<MoveStatusData>(entity).status == MoveStatus.Turn)
                return true;
            return false;
        }

        public float GetProgress()
        {
            var entity = _self.GetEntity();
            if (ObjectService.EntityManager.HasComponent<MoveData>(entity))
                return ObjectService.EntityManager.GetComponentData<MoveData>(entity).progress;

            return 0;
        }

        public void Stop()
        {
            // Debug.LogErrorFormat("Stop {0}", _moveStatus);
            stopTime = Global.gameTime;
            _lastMoveStatus = _moveStatus;
            _moveStatus = MoveStatus.Stop;
            var entity = _self.GetEntity();
            ObjectService.EntityManager.AddComponentData(entity, new MoveStatusData{status = MoveStatus.Stop});
        }

        public void Resume()
        {
            // Debug.LogErrorFormat("Resume {0}", _lastMoveStatus);
            _moveStatus = _lastMoveStatus;
            var entity = _self.GetEntity();
            var moveData = ObjectService.EntityManager.GetComponentData<MoveData>(entity);
            moveData.waitTime += Global.gameTime - stopTime;
            ObjectService.EntityManager.SetComponentData(entity, moveData);
            ObjectService.EntityManager.AddComponentData(entity, new MoveStatusData{status = _moveStatus});
        }

        public void End()
        {
            // Debug.LogErrorFormat("End {0}", _moveStatus);
            _moveStatus = MoveStatus.None;
            var entity = _self.GetEntity();
            ObjectService.EntityManager.AddComponentData(entity, new MoveStatusData { status = MoveStatus.None });
            _self.OnMoveStop();
            if (endCb != null)
            {
                endCb();
                endCb = null;
            }
        }

        public void None()
        {
            _moveStatus = MoveStatus.None;
            var entity = _self.GetEntity();
            ObjectService.EntityManager.AddComponentData(entity, new MoveStatusData { status = MoveStatus.None });
        }

        private int FindIndex(Vector2Int p, Vector2Int[] nps)
        {
            for (var j = 0; j < nps.Length; j++)
                if (p == nps[j])
                    return j;

            return 0;
        }

        private int FindOffset(Vector2Int[] ps1, Vector2Int[] ps2)
        {
            for (var i = 0; i < ps1.Length; i++)
            {
                // Debug.LogWarningFormat("index->{0} Find offset: {1} {2}", _self.GetIndex(), ps1[i], ps2[0]);
                if (ps2[0] == ps1[i]) return i;
            }

            return -1;
        }

        private Vector2Int[] Splicing(Vector2Int[] ps1, Vector2Int[] ps2, int i)
        {
            // Debug.LogWarningFormat("index->{0} Splicing: {1} {2} {3}", _self.GetIndex(), ps1.Length, ps2.Length, i);
            if (i == -1) return ps2;
            var list = new Vector2Int[i + ps2.Length];
            for (var j = 0; j < i; j++) list[j] = ps1[j];
            for (var j = 0; j < ps2.Length; j++) list[i + j] = ps2[j];
            return list;
        }

        // TODO 加速减速还可以优化 根据索引计算具体距离
        public void MoveHexPosition(Vector2Int[] ps, int i, Vector2Int[] pps, int pi)
        {
            // Debug.LogErrorFormat("move {0} {1} {2}", index, i, position==ps[i]);
            // if (lastPosition == ps[i]) return;
            mode = PathMode.Hex;
            Log("MoveHexPosition", "index->{0} Move: {1} {2} {3} {4}", status, index, position,
                pIndex, cIndex);
            if (!IsMoving()) _self.OnMoveStart();
            if (i >= ps.Length - 1) return;
            
            lastMoveTime = Global.gameTime;
            
            positions = ps;
            index = i;
            planPositions = pps;
            pIndex = pi;
            currentPositions = ps;
            type = PathMoveType.Start;
            step = PathMoveStep.Start;
            status = PathStatus.Move;
            position = currentPositions[index];
            nextPosition = positions[index + 1];
            // Log("MoveHexPositionInit", "index->{0} position->{1} nextPosition-{2}", index, position, nextPosition);
            _pathNotice?.StartPath(positions, i, pps, pi);
            if (!IsMoving()) _notice?.OnStartUp();
            return;
            
            
            switch (status)
            {
                case PathStatus.Move:
                    if (type == PathMoveType.End)
                    {
                        Log("MoveHexPosition", "index->{0} Move: End->Start", _self.GetIndex());
                        // 正在移动到最后位置，包括arrive和wait过程中受到新的移动消息
                        positions = ps;
                        index = FindIndex(position, positions);
                        // 如果索引大于下发索引，可能当前位置
                        if (index > i) index = i;
                        planPositions = pps;
                        pIndex = pi;
                        currentPositions = ps;
                        cIndex = i;
                        type = PathMoveType.Start;
                        step = PathMoveStep.Start;
                        status = PathStatus.Move;
                        position = currentPositions[index];
                        nextPosition = positions[index + 1];
                        _pathNotice?.StartPath(positions, index, pps, pi);
                        ChangeSpeed(ps[i], true);
                    }
                    else if (pi == 1 && !MathTools.CheckSame(currentPositions, ps))
                    {
                        Log("MoveHexPosition", "index->{0} Move: Change", _self.GetIndex());
                        // 如果不是当前路径 则切换路径开始移动
                        positions = ps;
                        index = i;
                        planPositions = pps;
                        pIndex = pi;
                        currentPositions = ps;
                        cIndex = i;
                        type = PathMoveType.Start;
                        step = PathMoveStep.Start;
                        status = PathStatus.Move;
                        position = currentPositions[index];
                        nextPosition = positions[index + 1];
                        _pathNotice?.StartPath(positions, i, pps, pi);
                        ChangeSpeed(ps[i], true);
                    }
                    else if (pi > pIndex)
                    {
                        Log("MoveHexPosition", "index->{0} Move: Splicing", _self.GetIndex());
                        // 如果移动中 下发路径为下一段路径则记录并加速
                        var mnps = Splicing(currentPositions, ps, FindOffset(currentPositions, ps));
                        index = FindIndex(positions[index], mnps);
                        positions = mnps;
                        currentPositions = ps;
                        cIndex = i;
                        planPositions = pps;
                        pIndex = pi;
                        _pathNotice?.RefreshPath(positions, index, pps, pi);
                    }
                    else if (pi == pIndex)
                    {
                        var ii = FindIndex(ps[i], positions);
                        if (index > ii)
                        {
                            Log("MoveHexPosition", "index->{0} Move: Fast", _self.GetIndex());
                            ChangeSpeed(ps[i], false);
                        }
                        else if (index < ii)
                        {
                            Log("MoveHexPosition", "index->{0} Move: Slow", _self.GetIndex());
                            ChangeSpeed(ps[i], true);
                        }

                        UpdateSpeed();
                    }

                    break;
                case PathStatus.Stop:
                    Log("MoveHexPosition", "index->{0} Move: Stop", _self.GetIndex());
                    // 如果移动中 下发路径为下一段路径则记录 执行这里说明消息延迟了， 判断索引进行加速
                    var nps = Splicing(currentPositions, ps, FindOffset(currentPositions, ps));
                    index = FindIndex(positions[index], nps);
                    positions = nps;
                    currentPositions = ps;
                    cIndex = i;
                    planPositions = pps;
                    pIndex = pi;
                    status = PathStatus.Move;
                    _pathNotice?.RefreshPath(positions, index, pps, pi);
                    ChangeSpeed(ps[i], true);
                    break;
                case PathStatus.Wait:
                    Log("MoveHexPosition", "index->{0} Move: Wait", _self.GetIndex());
                    // 已经提前到达，在收到当前位置则继续等待
                    if (i == ps.Length - 1) return;
                    Log("MoveHexPosition", "Move: Wait Go", _self.GetIndex());
                    positions = ps;
                    index = i;
                    planPositions = pps;
                    pIndex = pi;
                    currentPositions = ps;
                    type = PathMoveType.Start;
                    step = PathMoveStep.Start;
                    status = PathStatus.Move;
                    position = currentPositions[index];
                    nextPosition = positions[index + 1];
                    _pathNotice?.UpdatePath(positions, i, pps, pi);
                    break;
                case PathStatus.Stay:
                    Log("MoveHexPosition", "index->{0} Move: Stay", _self.GetIndex());
                    positions = ps;
                    index = i;
                    planPositions = pps;
                    pIndex = pi;
                    currentPositions = ps;
                    type = PathMoveType.Start;
                    step = PathMoveStep.Start;
                    status = PathStatus.Move;
                    position = currentPositions[index];
                    nextPosition = positions[index + 1];
                    _pathNotice?.StartPath(positions, i, pps, pi);
                    _notice?.OnStartUp();
                    // ChangeSpeed(0.9f);
                    break;
            }
        }

        public void StopHexPosition(Vector2Int p)
        {
            Log("StopHexPosition", "index->{0} Stop: {1} {2}", _self.GetIndex(), p, status);
            // 如果停止位置是路径终点则加速移动 否则强制移动到停止点
            if (IsMoving() || lastPosition != p)
            {
                position = p;
                index = 0;
                positions = new[] { position };
                cIndex = 0;
                planPositions = new[] { position };
                pIndex = 0;
                status = PathStatus.Move;
                type = PathMoveType.End;
                step = PathMoveStep.Start;

                _notice?.OnJoin(p);
                _pathNotice?.Stop(p);
                ChangeSpeed(p, true);
                OnUpdate();
            }
        }

        private void Arrive()
        {
            Log("Arrive");
            status = PathStatus.Stay;
            step = PathMoveStep.Ready;
            UpdateSpeed();
            End();
            _notice?.OnStay();
            _pathNotice?.Arrive();
        }

        private void Wait()
        {
            Log("Wait");
            status = PathStatus.Wait;
            step = PathMoveStep.Ready;
            UpdateSpeed();
            End();
            _notice?.OnStay();
        }

        public void Clear()
        {
            if (IsMoving())
            {
                End();
            }
            else
            {
                None();
            }
            status = PathStatus.Stay;
            var ps = new Vector2Int[] { };
            index = 0;
            pIndex = 0;
            cIndex = 0;
            positions = ps;
            planPositions = ps;
            currentPositions = ps;
        }

        public void OnUpdate()
        {
            if (_moveStatus == MoveStatus.Stop) return;
            switch (status)
            {
                case PathStatus.Move:
                    Move();
                    break;
            }
        }

        public void UpdateSpeed()
        {
            var s = _self.GetMoveSpeed();
            UpdateSpeed(s);
        }

        private void ChangeSpeed(Vector2Int p, bool b)
        {
            // Debug.LogWarningFormat("index->{0} Change Speed: {1} -> {2} -> {3}", _self.GetIndex(), lastPosition, p,
                // 1 + Vector3.Distance(_self.GetPosition(), HexCube.FromOffset(p).ToPosition()) / 0.86f);
            ChangeSpeed(HexCube.FromOffset(p).ToPosition(), b);
        }

        private void ChangeSpeed(Vector3 p, bool b)
        {
            ChangeSpeed(1 + Vector3.Distance(_self.GetPosition(), p) / 0.86f * (b ? 1 : -1));
        }

        private void ChangeSpeed(float f)
        {
            var s = _self.GetMoveSpeed();
            UpdateSpeed(s * f);
        }

        private bool ResetPosition()
        {
            lastPosition = position;
            if (type == PathMoveType.End)
            {
                if (index >= positions.Length - 1 && pIndex >= planPositions.Length - 1)
                    Arrive();
                else
                    Wait();

                return false;
            }

            if (index >= positions.Length)
            {
                Wait();
                return false;
            }

            if (index == positions.Length - 1)
            {
                position = positions[index];
            }
            else
            {
                prePosition = positions[index - 1];
                position = positions[index];
                nextPosition = positions[index + 1];
                // 如果再指定位置未收到更新plan则stop
                if (pIndex < planPositions.Length - 2 && index > positions.Length - 3) status = PathStatus.Stop;
            }

            // Debug.LogErrorFormat("Next {0} {1}", lastPosition, position);
            _pathNotice?.Change(index, pIndex);
            return true;
        }

        private void Next()
        {
            // 如果没有新的坐标就取消
            if (!ResetPosition()) return;

            if (index >= positions.Length - 1)
                type = PathMoveType.End;
            else if (MathTools.IsTurn(prePosition, position, nextPosition))
                type = PathMoveType.Turn;
            else
                type = PathMoveType.Line;
            status = PathStatus.Move;
            step = PathMoveStep.Start;
            _notice?.OnJoin(position);
        }

        private void Move()
        {
            switch (step)
            {
                case PathMoveStep.Start:
                    // Debug.LogError("PathMoveStepStart");
                    switch (type)
                    {
                        case PathMoveType.Start:
                            MoveInit(_self.GetPosition(), MathTools.GetMiddle(position, nextPosition));
                            break;
                        case PathMoveType.End:
                            MoveInit(_self.GetPosition(), HexCube.FromOffset(position).ToPosition());
                            break;
                        case PathMoveType.Line:
                            MoveLineInit(_self.GetPosition(), MathTools.GetMiddle(position, nextPosition));
                            break;
                        case PathMoveType.Turn:
                            MoveTurnInit(MathTools.GetMiddle(prePosition, position),
                                HexCube.FromOffset(position).ToPosition(), MathTools.GetMiddle(position, nextPosition));
                            break;
                    }

                    step = PathMoveStep.Check;
                    Move();
                    break;
                case PathMoveStep.Check:
                    var moveData = ObjectService.EntityManager.GetComponentData<MoveData>(_self.GetEntity());
                    var moveStatusData = ObjectService.EntityManager.GetComponentData<MoveStatusData>(_self.GetEntity());
                    // Debug.LogErrorFormat("End: {0} {1} {2} {3} {4} {5} {6}", data.position, data.start, data.end, data.progress, data.distance, data.speed, status.status);
                    // Debug.LogErrorFormat("PathMoveStepEnd: {0}", moveData.progress);
                    
                    switch (type)
                    {
                        case PathMoveType.Start:
                            if (moveData.progress == 0) _notice?.OnDestination(endPosition);
                            break;
                        case PathMoveType.End:
                            if (moveData.progress == 0) _notice?.OnDestination(HexCube.FromOffset(position).ToPosition());
                            if (moveData.progress == 1) _notice?.OnReach(position);
                            break;
                        case PathMoveType.Line:
                        case PathMoveType.Turn:
                            if (moveData.progress == 0) _notice?.OnDestination(HexCube.FromOffset(position).ToPosition());
                            if (process < 0.5f && moveData.progress >= 0.5f)
                            {
                                _notice?.OnReach(position);
                                _notice?.OnDestination(endPosition);
                            }
                            break;
                    }
                    
                    if (moveData.progress == 1)
                    {
                        index += 1;
                        lastMoveTime = moveData.endTime + moveData.waitTime;
                        // step = PathMoveStep.Ready;
                        Next();
                        UpdateSpeed();
                        OnUpdate();
                    }
                    else
                    {
                        // if (process < 0.5f && moveData.progress >= 0.5f)
                        // {
                        //     if (moveStatusData.status == MoveStatus.Turn)
                        //     {
                        //         _notice?.OnDestination(endPosition);
                        //     }
                        // }
                    
                        // Debug.LogErrorFormat("PathMoveStep process: {0}", moveData.progress);
                    }
                    process = moveData.progress;
                    // MoveData moveData = ObjectService.EntityManager.GetComponentData<MoveData>(_self.GetEntity());
                    // MoveStatusData moveStatusData = ObjectService.EntityManager.GetComponentData<MoveStatusData>(_self.GetEntity());
                    // if (moveData.progress == 1)
                    // {
                    //     index += 1;
                    //     step = PathMoveStep.Ready;
                    //     Next();
                    //     UpdateSpeed();
                    //     OnUpdate();
                    // }
                    // else
                    // {
                    //     if (moveStatusData.status == MoveStatus.Turn)
                    //     {
                    //         if (process < 0.5f && moveData.progress > 0.5f)
                    //         {
                    //             _notice?.OnDestination(moveData.end);
                    //         }
                    //     }
                    //
                    //     process = moveData.progress;
                    // }

                    break;
            }
        }

        private void MoveInit(Vector2Int start, Vector2Int end)
        {
            Vector3 s;
            Vector3 e;
            switch (mode)
            {
                case PathMode.Hex:
                    s = HexCube.FromOffset(start).ToPosition();
                    e = HexCube.FromOffset(end).ToPosition();
                    break;
                default:
                    s = new Vector3(start.x, 0, start.y);
                    e = new Vector3(end.x, 0, end.y);
                    break;
            }
            MoveInit(s, e);
        }

        private void MoveInit(Vector3 start, Vector2Int end)
        {
            Vector3 s;
            Vector3 e;
            switch (mode)
            {
                case PathMode.Hex:
                    e = HexCube.FromOffset(end).ToPosition();
                    break;
                default:
                    e = new Vector3(end.x, 0, end.y);
                    break;
            }
            MoveInit(start, e);
        }

        private void MoveInit(Vector3 start, Vector3 end)
        {
            Log("MoveInit", "{0} {1}", start, end);
            startPosition = start;
            endPosition = end;
            SetLine(startPosition, endPosition, (float)_self.GetMoveSpeedTime() / 2);
            //LookPosition(endPosition);
        }

        private void MoveLineInit(Vector3 start, Vector3 end)
        {
            Log("MoveLineInit", "{0} {1}", start, end);
            startPosition = start;
            endPosition = end;
            SetLine(startPosition, endPosition, (float)_self.GetMoveSpeedTime());
            //LookPosition(endPosition);
        }

        private void MoveTurnInit(Vector3 start, Vector3 middle, Vector3 end)
        {
            // Debug.LogErrorFormat("MoveTurnInit {0} {1} {2}", start, middle, end);
            Log("MoveTurnInit", "{0} {1} {2}", start, middle,  end);
            startPosition = start;
            endPosition = end;
            SetTurn(start, middle, end, (float)_self.GetMoveSpeedTime());
            //LookForWard();
        }

        protected void Log(string t)
        {
            if (_self.IsDebug())
                LogTools.Info("{0} id->{1} index->{2} {3}", _self.GetName(), _self.GetId(), _self.GetIndex(), t);
        }

        protected void Log(string t, string s, params object[] p)
        {
            var text = string.Format(s, p);
            if (_self.IsDebug())
                LogTools.Info("{0} id->{1} index->{2} {3} {4}", _self.GetName(), _self.GetId(), _self.GetIndex(), t,
                    text);
        }

        public interface Notice
        {
            void OnJoin(Vector2Int position);
            void OnDestination(Vector3 position);
            void OnReach(Vector2Int position);
            void OnStay();
            void OnStartUp();
        }

        public interface PathNotice
        {
            void StartPath(Vector2Int[] positions, int index, Vector2Int[] planPositions, int planIndex);
            void UpdatePath(Vector2Int[] positions, int index, Vector2Int[] planPositions, int planIndex);
            void RefreshPath(Vector2Int[] positions, int index, Vector2Int[] planPositions, int planIndex);
            void AddPath(Vector2Int[] positions, int planIndex);
            void Change(int index, int planIndex);
            void Arrive();
            void Stop(Vector2Int p);
        }

        private enum PathMode
        {
            Default,
            Hex
        }

        private enum PathStatus
        {
            Stay,
            Wait,
            Move,
            Stop,
            Next
        }

        private enum PathMoveStep
        {
            Ready,
            Start,
            Check,
            End
        }

        private enum PathMoveType
        {
            Start,
            Line,
            Turn,
            End
        }
    }
}